﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using centraldba_library.Data;

namespace centraldba_dbrestore_utility
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, IDisposable
    {
        System.Data.DataTable dtSource;
        System.Data.DataTable dtDestination;
        bool isLoadingBackups;
        string newlySelectedServer;
        DateTime SelectedDate;
        recovery_manager rman;

        public MainWindow()
        {
            InitializeComponent();

            // Init global variable
            isLoadingBackups = false;

            // Initialize dtSource and dtDestination
            LoadConnections();

            // Initialize the interface to data
            rman = new recovery_manager(Properties.Settings.Default.ConnectionStringTemplate, Properties.Settings.Default.centraldba_server_name, Properties.Settings.Default.centraldba_db_name);

            // Set binding settings
            dtSource.DefaultView.Sort = "orderBy, connection";
            SourceConnection.ItemsSource = dtSource.DefaultView;

            dtDestination.DefaultView.Sort = "orderBy, connection";
            DestinationConnection.ItemsSource = dtDestination.DefaultView;

            SelectedDate = DateTime.Now.Date;
            stopat_time.Value = DateTime.Now;
        }

        #region IDisposable Support
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // Release recovery manager object
                    if (rman != null)
                    {
                        rman = null;
                    }

                    if (dtSource != null)
                    {
                        dtSource.Dispose();
                        dtSource = null;
                    }
                    if (dtDestination != null)
                    {
                        dtDestination.Dispose();
                        dtDestination = null;
                    }
                }

                newlySelectedServer = null;
                disposedValue = true;
            }
        }

        // This code added to correctly implement the disposable pattern.
        public void Dispose()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(true);
        }
        #endregion

        private void LoadConnections()
        {
            string sAppServers = centraldba_dbrestore_utility.Properties.Settings.Default.AppSQLServers.ToString();
            string sUserServers = centraldba_dbrestore_utility.Properties.Settings.Default.MySQLServers.ToString();
            System.Xml.XmlDocument appServers = new System.Xml.XmlDocument();
            System.Xml.XmlDocument userServers = new System.Xml.XmlDocument();

            // Initialize null objects
            if (dtSource == null)
            {
                dtSource = new System.Data.DataTable("SourceConnections");
                dtSource.Columns.Add("orderBy");
                dtSource.Columns.Add("connection");
            }
            if (dtDestination == null)
            {
                dtDestination = new System.Data.DataTable("DestinationConnections");
                dtDestination.Columns.Add("orderBy");
                dtDestination.Columns.Add("connection");
            }

            // Clear current data
            dtSource.Clear();
            dtDestination.Clear();

            // Load Mandatory Settings (from appServers)
            appServers.LoadXml(sAppServers);
            foreach (System.Xml.XmlNode xn in appServers.SelectNodes("/servers/server"))
            {
                System.Data.DataRow drSource = dtSource.NewRow();
                drSource["orderBy"] = Convert.ToInt16(xn.Attributes["order"].Value.ToString());
                drSource["connection"] = xn.InnerText.Replace("[VAR_DBTYPE]", "Source");
                dtSource.Rows.Add(drSource);

                System.Data.DataRow drDestination = dtDestination.NewRow();
                drDestination["orderBy"] = Convert.ToInt16(xn.Attributes["order"].Value.ToString());
                drDestination["connection"] = xn.InnerText.Replace("[VAR_DBTYPE]", "Destination");
                dtDestination.Rows.Add(drDestination);
            }
            appServers = null;

            // Load User Settings (userServers)
            if (!sUserServers.Length.Equals(0))
            {
                userServers.LoadXml(sUserServers);
                foreach (System.Xml.XmlNode xn in userServers.SelectNodes("/servers/server"))
                {
                    System.Data.DataRow drSource = dtSource.NewRow();
                    drSource["orderBy"] = Convert.ToInt16(3);
                    drSource["connection"] = xn.InnerText;
                    dtSource.Rows.Add(drSource);

                    System.Data.DataRow drDestination = dtDestination.NewRow();
                    drDestination["orderBy"] = Convert.ToInt16(3);
                    drDestination["connection"] = xn.InnerText;
                    dtDestination.Rows.Add(drDestination);
                }
                userServers = null;
            }
        }

        private void ClearRecentConnections()
        {
            centraldba_dbrestore_utility.Properties.Settings.Default.MySQLServers = String.Empty;
            centraldba_dbrestore_utility.Properties.Settings.Default.Save();

            LoadConnections();
        }

        private void cmdAbout_Click(object sender, RoutedEventArgs e)
        {
            frmAbout frmAbout = new frmAbout();
            frmAbout.Owner = this;
            frmAbout.ShowDialog();
            frmAbout = null;
        }

        private void SourceConnection_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string destinationSelected = String.Empty;

            if (!e.AddedItems.Count.Equals(0))
            {
                Int16 theValue = Convert.ToInt16(((System.Data.DataRowView)e.AddedItems[0])["orderBy"]);
                if (theValue.Equals(1))     // Select Connection (show frmConnect)
                {
                    // Retain what is currently selected for the destination
                    if (DestinationConnection.SelectedIndex >= 0) destinationSelected = DestinationConnection.Text;

                    // Get a new connection item
                    frmConnect fc = new frmConnect();
                    fc.Owner = this;
                    fc.ConnectionSelected += Fc_ConnectionSelected;
                    fc.ShowDialog();
                    fc = null;

                    // Reload the Connection Drop Downs
                    LoadConnections();
                    SourceConnection.Text = newlySelectedServer;
                    if (destinationSelected.Length.Equals(0))
                        DestinationConnection.Text = newlySelectedServer;
                    else
                        DestinationConnection.Text = destinationSelected;
                }

                // Clear Recent Connections
                else if (theValue.Equals(2))
                {
                    ClearRecentConnections();
                }

                // Retrieve the list of backups
                else if (SourceConnection.SelectedIndex > 1)
                {
                    LoadBackups();
                    if (DestinationConnection.Text.Length.Equals(0))
                        DestinationConnection.Text = ((System.Data.DataRowView)SourceConnection.SelectedItem)["connection"].ToString();
                }
            }
        }

        private void DestinationConnection_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string sourceSelected = String.Empty;

            if (!e.AddedItems.Count.Equals(0))
            {
                Int16 theValue = Convert.ToInt16(((System.Data.DataRowView)e.AddedItems[0])["orderBy"]);
                if (theValue.Equals(1))     // Select Connection (show frmConnect)
                {
                    // Retain what is currently selected for the source
                    if (SourceConnection.SelectedIndex >= 0) sourceSelected = SourceConnection.Text;

                    // Get a new connection item
                    frmConnect fc = new frmConnect();
                    fc.Owner = this;
                    fc.ConnectionSelected += Fc_ConnectionSelected;
                    fc.ShowDialog();
                    fc = null;

                    // Reload the Connection Drop Downs
                    LoadConnections();
                    DestinationConnection.Text = newlySelectedServer;
                    if (sourceSelected.Length.Equals(0))
                        SourceConnection.Text = newlySelectedServer;
                    else
                        SourceConnection.Text = sourceSelected;
                }

                // Clear Recent Connections
                else if (theValue.Equals(2))
                {
                    ClearRecentConnections();
                }
            }
        }

        private void Fc_ConnectionSelected(object sender, ConnectionEventArgs e)
        {
            newlySelectedServer = e.Connection;
        }

        private void TodayDate_Click(object sender, RoutedEventArgs e)
        {
            // Set date to today
            SelectedDate = DateTime.Now.Date;
            stopat_time.Value = DateTime.Now;

            // Now pass the click event on to the RadioButton group handler
            RadioButton_Click(sender, e);
        }

        private void CustomDate_Click(object sender, RoutedEventArgs e)
        {
            // Get specific date
            frmPickDate fPickDate = new frmPickDate(SelectedDate);
            fPickDate.DateSelected += FPickDate_DateSelected;
            fPickDate.Owner = this;
            fPickDate.ShowDialog();
            fPickDate = null;

            // Now pass the click event on to the RadioButton group handler
            RadioButton_Click(sender, e);
        }

        private void FPickDate_DateSelected(object sender, DateEventArgs e)
        {
            SelectedDate = e.SelectedDate.Date;
            stopat_time.Value = SelectedDate.Add(new TimeSpan(0, 23, 59, 59, 99));
        }

        private void RadioButton_Click(object sender, RoutedEventArgs e)
        {
            LoadBackups();
        }

        private void dgDatabaseBackups_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
        {
            int selected_count = 0;

            if (dgDatabaseBackups.SelectedItems == null)
                selected_count = 0;
            else
                selected_count = dgDatabaseBackups.SelectedItems.Count;

            if (!selected_count.Equals(0))
            {
                cmdRestore.IsEnabled = true;
                cmdScript.IsEnabled = true;
            }
            else if (selected_count.Equals(0))
            {
                cmdRestore.IsEnabled = false;
                cmdScript.IsEnabled = false;
            }
        }


        private void EnableRibbon(bool isEnabled)
        {
            busyDatabaseBackups.IsBusy = !isEnabled;
            TodayDate.IsEnabled = isEnabled;
            AllFiles.IsEnabled = isEnabled;
            RecoveryWindow.IsEnabled = isEnabled;
            CustomDate.IsEnabled = isEnabled;
            bkpFileExists.IsEnabled = isEnabled;
            SourceConnection.IsEnabled = isEnabled;
        }

        private void LoadBackups()
        {
            // An actual database needs to be selected.  If not, exit.
            if (SourceConnection.SelectedIndex < 1) return;


            // If the backup list isn't currently loading, load the backup list
            if (!isLoadingBackups)
            {
                // Mark that backup list is loading
                isLoadingBackups = true;

                try
                {
                    // Load data into the table Server. You can modify this code as needed.
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.WorkerReportsProgress = false;
                    bw.WorkerSupportsCancellation = false;

                    #region Background worker - run the load backup file list
                    bw.DoWork += (o, ea) =>
                    {
                        // Grab requisite data
                        string[] args = (string[])ea.Argument;
                        string server_name = args[0].ToString().Trim();
                        string database_name = args[1].ToString().Trim();

                        // Bind the data
                        string backup_label = args[2].ToString().Trim();
                        string stopat = args[3].ToString().Trim();
                        bool files_exist = Boolean.Parse(args[4].ToString().Trim());
                        bool recovery_window = Boolean.Parse(args[5].ToString().Trim());

                        // Get the backup list (server, db, date, label = retrieval query only)
                        try
                        {
                            ea.Result = rman.GetAllBackups(server_name, database_name, stopat, backup_label, files_exist, recovery_window);
                        }
                        catch (Exception ex)
                        {
                            Dispatcher.BeginInvoke((Action)delegate
                            {
                                DisplayError(ex, "Failure Updating Backup List");
                            });
                        }
                    };
                    #endregion

                    #region Background worker - run the load backup file list Completed
                    bw.RunWorkerCompleted += (o, ea) =>
                    {
                        // Get the current sort
                        SortDescription[] sdc = new SortDescription[dgDatabaseBackups.Items.SortDescriptions.Count];
                        dgDatabaseBackups.Items.SortDescriptions.CopyTo(sdc, 0);

                        // Set the updated data source
                        dgDatabaseBackups.ItemsSource = (ObservableCollection<backup>)ea.Result;

                        // Set the sort
                        if (sdc.Length.Equals(0))
                        {
                            // Default sort
                            dgDatabaseBackups.Items.SortDescriptions.Add(new SortDescription("id", ListSortDirection.Ascending));
                        }
                        else
                        {
                            // Restore the current sort
                            foreach (SortDescription sd in sdc)
                            {
                                dgDatabaseBackups.Items.SortDescriptions.Add(sd);
                            }
                        }

                        // Mark that backup list is not loading
                        isLoadingBackups = false;
                        EnableRibbon(true);
                    };
                    #endregion

                    EnableRibbon(false);

                    string selectedItem = ((System.Data.DataRowView)SourceConnection.SelectedItem)["connection"].ToString();
                    string server = selectedItem.Split('.')[0];
                    string database = selectedItem.Split('.')[1];
                    string start_date = "";
                    bool rec_window = RecoveryWindow.IsChecked.Value;

                    if (!(rec_window || AllFiles.IsChecked.Value))
                        start_date = SelectedDate.Date.ToString();

                    // TODO - Backup label is hard-coded as nothing
                    bw.RunWorkerAsync(new string[] { server, database, String.Empty, start_date, bkpFileExists.IsChecked.ToString(), rec_window.ToString() });
                }
                catch (Exception ex)
                {
                    DisplayError(ex, "Loading List of Database Backups");
                }
            }
        }

        private void cmdRestore_Click(object sender, RoutedEventArgs e)
        {
            // A backup has to be selected.  If not, return
            if (dgDatabaseBackups.SelectedIndex < 0) return;

            // Declare Local Variables
            MessageBoxResult answer;
            string cap = "Restore Database";
            string selectedItem = ((System.Data.DataRowView)SourceConnection.SelectedItem)["connection"].ToString();
            string src_inst = selectedItem.Split('.')[0];
            string src_db = selectedItem.Split('.')[1];
            selectedItem = ((System.Data.DataRowView)DestinationConnection.SelectedItem)["connection"].ToString();
            string dest_inst = selectedItem.Split('.')[0];
            string dest_db = selectedItem.Split('.')[1];
            string restorePath = src_inst + "/" + src_db + " to " + dest_inst + "/" + dest_db;

            // Ensure a restore is desired
            answer = Xceed.Wpf.Toolkit.MessageBox.Show("Are you sure you wish to perform the restore listed below?\n\n" + restorePath, cap, MessageBoxButton.OKCancel, MessageBoxImage.Question, MessageBoxResult.Cancel);

            // Perform the restore
            if (answer == MessageBoxResult.OK)
            {
                try
                {
                    frmStatusWindow sw1 = new frmStatusWindow();
                    sw1.Owner = this;
                    // TODO - Backup label is hard-coded as nothing
                    sw1.RestoreDatabase(src_inst, dest_inst, src_db, dest_db, String.Empty, ((backup)dgDatabaseBackups.SelectedItem).backup_set_id, stopat_time.Value.GetValueOrDefault(DateTime.Now).ToString());
                    sw1.ShowDialog();
                }
                catch (Exception ex)
                {
                    DisplayError(ex, cap);
                }
            }

            // Cancel the restore
            else
            {
                Xceed.Wpf.Toolkit.MessageBox.Show("You chose not to perform the restore listed below.\n\n" + restorePath, cap);
            }

        }

        private void cmdScript_Click(object sender, RoutedEventArgs e)
        {
            // A backup has to be selected.  If not, return
            if (dgDatabaseBackups.SelectedIndex < 0) return;

            // Declare Local Variables
            StringBuilder sb = new StringBuilder();
            string selectedItem = ((System.Data.DataRowView)SourceConnection.SelectedItem)["connection"].ToString();
            string src_inst = selectedItem.Split('.')[0];
            string src_db = selectedItem.Split('.')[1];
            selectedItem = ((System.Data.DataRowView)DestinationConnection.SelectedItem)["connection"].ToString();
            string dest_db = selectedItem.Split('.')[1];

            // Build the restore command list
            // TODO - Backup label is hard-coded as nothing
            foreach (restore_script s in rman.GetRestoreScripts(src_inst, src_db, dest_db, String.Empty, ((backup)dgDatabaseBackups.SelectedItem).backup_set_id, stopat_time.Value.GetValueOrDefault(DateTime.Now).ToString()))
            {
                sb.AppendLine(s.Command);
            }

            // Copy the command to the clipboard
            if (!sb.Length.Equals(0))
            {
                Clipboard.SetText(sb.ToString());
                sb.AppendLine("\n\nThis text has been copied to your clipboard.");

                // Display the restore script
                DisplayMessage(sb.ToString(), "Restore Script Preview");

                // Cleanup
                sb.Clear();
                sb = null;
            }
            else
            {
                DisplayMessage("There was nothing found to execute.", "Restore Script Preview");
            }

        }



        /// <summary>
        /// Display an Error Message Popup Window
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="errorCaption"></param>
        private void DisplayError(Exception ex, string errorCaption)
        {
            // Declare Local Variables
            StringBuilder sb = new StringBuilder();

            // Add the Error Message
            sb.Append(ex.Message.ToString());

            // Add the Stack Trace
            if (!ex.StackTrace.Length.Equals(0))
            {
                sb.Append("\n\n");
                sb.Append(ex.StackTrace.ToString());
            }

            // Display the Error
            Xceed.Wpf.Toolkit.MessageBox.Show(this, sb.ToString(), errorCaption, MessageBoxButton.OK, MessageBoxImage.Error);

            // Cleanup
            sb.Clear();
            sb = null;
        }

        /// <summary>
        /// Display an Information Message Popup Window
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="errorCaption"></param>
        private void DisplayMessage(string message, string messageCaption)
        {
            Xceed.Wpf.Toolkit.MessageBox.Show(this, message, messageCaption, MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void cmdConfigure_Click(object sender, RoutedEventArgs e)
        {
            frmConfigure cfg = new frmConfigure();
            cfg.Owner = this;
            cfg.ShowDialog();
            cfg = null;
        }
    }
}
